package edu.gmu.hodum.sei.bluetooth;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.UUID;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.IBinder;

class BluetoothCommSvc extends Service implements Observer{

	//private final static int REQUEST_ENABLE_BT = 1;
	private final static List<BluetoothIntentConn> btConnList = new ArrayList <BluetoothIntentConn>();;
	private final static BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCreate() {
		//sets up the service and the communications components
		System.out.println("BluetoothCommSvc onCreate");

		//if the intent indicates that this device is the "phone" application with greater resources
		//setup as the bluetooth server
		
		//else, setup as the bluetooth client
	}
	
	public int onStartCommand(Intent intent, int flags, int StartId){
		System.out.println("BluetoothCommSvc onStartCommand");
		
		broadcast(intent);
		// We want this service to continue running until it is explicitly
        // stopped, so return sticky.
		return START_STICKY;
	}
	
	public void setupBluetooth(){
		if (mBluetoothAdapter == null) {
		    // Device does not support Bluetooth
			System.out.println("BluetoothCommSvc device does not support Bluetooth!");
		}
		
		//enable bluetooth
		if (!mBluetoothAdapter.isEnabled()) {
			System.out.println("BluetoothCommSvc Bluetooth not enabled!");
			//TODO: startActivityForResult to enable Bluetooth
		    //Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
		    //startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
		}
		
		//set discoverable (value of 0 means always discoverable)
		Intent discoverableIntent = new
				Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
				discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
				startActivity(discoverableIntent);
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		
		//a new Bluetooth socket connection is set up, either as a server or as a client
		if (arg1 instanceof BluetoothSocket){
			BluetoothSocket btSoc = (BluetoothSocket) arg1;
			BluetoothIntentConn btConn = new BluetoothIntentConn(this, btSoc);
			btConnList.add(btConn);
		}
		//an intent was received from a connection, broadcast it 
		else if (arg1 instanceof Intent){
			Intent intent = (Intent) arg1;
			
			//TODO: may need to sanitize/modify intent before broadcast
			
			this.sendBroadcast(intent);
		}
		
	}
	
	//send intent to all Bluetooth connections
	public void broadcast(Intent intent){
		for (BluetoothIntentConn btConn : btConnList){
			btConn.sendIntent(intent);
		}
	}
	
	
	//attempts to connect to Bluetooth Device
	class ConnectThread extends Observable implements Runnable {
		private BluetoothDevice btDevice;
		
		ConnectThread (Observer observer, BluetoothDevice btDevice){
			this.addObserver(observer);
		}
		
		@Override
		public void run() {
			try {
				BluetoothSocket btSoc = btDevice.createRfcommSocketToServiceRecord(UUID.fromString(getString(R.string.app_name)));
				this.notifyObservers(btSoc);
			} catch (IOException e) {
				System.out.println("BluetoothCommSvc ConnectThread IOException");
				e.printStackTrace();
			}
			
		}
		
	}
	
	//if a Bluetooth server,
	//always running thread to listen for connecting devices 
	class AcceptThread extends Observable implements Runnable {
	    private final BluetoothServerSocket mmServerSocket;
	    
	    AcceptThread(Observer observer) {
	    	this.addObserver(observer);
	    	
	    	// Use a temporary object that is later assigned to mmServerSocket,
	        // because mmServerSocket is final
	        BluetoothServerSocket tmp = null;
	        try {
	            // TODO: MY_UUID is the app's UUID string, also used by the client code
	            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(getString(R.string.app_name), UUID.fromString(getString(R.string.app_name)));
	        } catch (IOException e) { }
	        mmServerSocket = tmp;
	    }
	 
	    public void run() {
	        BluetoothSocket socket = null;
	        // Keep listening until exception occurs or a socket is returned
	        while (true) {
	            try {
	                socket = mmServerSocket.accept();
	                this.notifyObservers(socket);
	            } catch (IOException e) {
	                break;
	            }
	        }
	    }
	 
	    /** Will cancel the listening socket, and cause the thread to finish */
	    public void cancel() {
	        try {
	            mmServerSocket.close();
	        } catch (IOException e) { }
	    }
	}
	
}
